import Point from "../../point/src/Point"

import Calc from "../../calc/src/Calc";

export default class Rect {
    /**
     * Gets or sets the left coordinate of this Rect.
     */
    public left: number;
    /**
     * Gets or sets the top coordinate of this Rect.
     */
    public top: number;
    /**
     * Gets or sets the width of this Rect.
     */
    public width: number;
    /**
     * Gets or sets the height of this Rect.
     */
    public height: number;
    /**
     * Initializes a new instance of the Rect class.
     *
     * @param left Left coordinate of the new Rect.
     * @param top Top coordinate of the new Rect.
     * @param width Width of the new Rect.
     * @param height Height of the new Rect.
     */
    constructor(left: number, top: number, width: number, height: number) {
        this.left = left;
        this.top = top;
        this.width = width;
        this.height = height;
    }
    /**
     * Gets the right coordinate of this Rect.
     */
    public get right(): number {
        return this.left + this.width;
    }
    /**
     * Gets the bottom coordinate of this Rect.
     */
    public get bottom(): number {
        return this.top + this.height;
    }
    /**
     * Returns true if a Rect has the same coordinates and dimensions
     * as this Rect.
     *
     * @param rc Rect to compare to this Rect.
     */
    public equals(rc: Rect): boolean {
        return (rc instanceof Rect) && this.left == rc.left && this.top == rc.top && this.width == rc.width && this.height == rc.height;
    }
    /**
     * Creates a copy of this Rect.
     */
    public clone(): Rect {
        return new Rect(this.left, this.top, this.width, this.height);
    }
    /**
     * Creates a Rect from <b>ClientRect</b> or <b>SVGRect</b> objects.
     *
     * @param rc Rectangle obtained by a call to the DOM's <b>getBoundingClientRect</b>
     * or <b>GetBoundingBox</b> methods.
     */
    public static fromBoundingRect(rc: any): Rect {
        if (rc.left != null) {
            return new Rect(rc.left, rc.top, rc.width, rc.height);
        } else if (rc.x != null) {
            return new Rect(rc.x, rc.y, rc.width, rc.height);
        } else {
            throw ('Invalid source rectangle.');
        }
    }
    /**
     * Gets a rectangle that represents the union of two rectangles.
     *
     * @param rc1 First rectangle.
     * @param rc2 Second rectangle.
     */
    public static union(rc1: Rect, rc2: Rect): Rect {
        let x = Math.min(rc1.left, rc2.left),
            y = Math.min(rc1.top, rc2.top),
            right = Math.max(rc1.right, rc2.right),
            bottom = Math.max(rc1.bottom, rc2.bottom);
        return new Rect(x, y, right - x, bottom - y);
    }
    /**
     * Gets a rectangle that represents the intersection of two rectangles.
     *
     * @param rc1 First rectangle.
     * @param rc2 Second rectangle.
     */
    public static intersection(rc1: Rect, rc2: Rect): Rect {
        let x = Math.max(rc1.left, rc2.left),
            y = Math.max(rc1.top, rc2.top),
            right = Math.min(rc1.right, rc2.right),
            bottom = Math.min(rc1.bottom, rc2.bottom);
        return new Rect(x, y, right - x, bottom - y);
    }
    /**
     * Determines whether the rectangle contains a given point or rectangle.
     *
     * @param pt The Point or Rect to ckeck.
     */
    public contains(pt: any): boolean {
        if (pt instanceof Point) {
            return pt.x >= this.left && pt.x <= this.right &&
                pt.y >= this.top && pt.y <= this.bottom;
        } else if (pt instanceof Rect) {
            let rc2 = pt as Rect;
            return rc2.left >= this.left && rc2.right <= this.right &&
                rc2.top >= this.top && rc2.bottom <= this.bottom;
        } else {
            throw('Point or Rect expected.');
        }
    }
    /**
     * Creates a rectangle that results from expanding or shrinking a rectangle by the specified amounts.
     *
     * @param dx The amount by which to expand or shrink the left and right sides of the rectangle.
     * @param dy The amount by which to expand or shrink the top and bottom sides of the rectangle.
     */
    public inflate(dx: number, dy: number): Rect {
        return new Rect(this.left - dx, this.top - dy, this.width + 2 * dx, this.height + 2 * dy);
    }
}